var mainTower = null;
var map;
var circleHover;
var money;
var paths = [];
var waitingForNResults = 0;
var defenseTowersAndCircles = []; //array of {tower:t, circle:circle}
var maxDistance = 0; // distance of the biggest path
var level = null;
var totalEnemies = 0;
var j = 1;
var timer_is_on = false;
var enemiesAndPaths = [];
var stopCreateEnemies = false;
var deadEnemies = new Array(0,0,0); //array: deadEnemies[type-1] = number
var createdTowers = new Array(0,0,0); //array: createdTowers[type-1] = number


function Engine() {
    this.init = function() {
        // Função inicializadora do jogo. Começa selecionando uma fase para jogar

        //acess storage
        var retrievedObject = JSON.parse(localStorage.getItem('db'));

        var levels = retrievedObject.levels;

        for (var i = 0; i < levels.length; i++) {
            var linkName = levels[i].name; 
            var link = "<a class='level' index="+ i +">" + linkName + "</a>";
            document.getElementById('select_level').innerHTML += link;
        };
    };
        
    this.run = function() {
        console.log('running level: ', level);
        //document.getElementById('game').innerHTML = "<span>$ <a id='money'></a> </span> <div id='map_canvas' style='width:100%; height:100%'></div>";

        setMoney(level.initialMoney)

        // prep map
        directionsDisplay = new google.maps.DirectionsRenderer({'suppressMarkers':true});
        var center = new google.maps.LatLng(level.destination.lat, level.destination.lng);
        var myOptions = {
            zoom:5,
            mapTypeId: google.maps.MapTypeId.ROADMAP,
            center: center
        }

        map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
        directionsDisplay.setMap(map);

        google.maps.event.addListener(map, 'rightclick', function(event) {
            showContextMenu(event.latLng);
        });
    
        google.maps.event.addListener(map, 'click', function(event) {
            hideContextMenu();
        });
    
        // create main tower
        var pos = new google.maps.LatLng(level.destination.lat, level.destination.lng);
		
		//http://img.informer.com/icons/png/48/1967/1967546.png
        mainTower = new MainTower({position:pos, map:map, life:level.maxLife, icon:"img/MainTower.gif"}); 
		document.getElementById("mainTowerLife").innerHTML = mainTower.life.toString();

        calcRoutesAndStartWave(pos);
    };
};

function startGame(index) {
    //acess storage
    var retrievedObject = JSON.parse(localStorage.getItem('db'));
    level = retrievedObject.levels[index];
    $("#game").show();
    $("#select_level").hide();
    engine.run();
}

function calcRoutesAndStartWave(destination) {
    var routes = [];
    var markers = []; //usado para acertar o zoom
    markers.push(destination);

    level.origins.forEach(function(origin) {
        var org = new google.maps.LatLng(origin.lat,origin.lng);
        routes.push({origin: org, destination: destination});
        markers.push(org);
    });

    var rendererOptions = {
        preserveViewport: true,         
        suppressMarkers:true,
        routeIndex:0
    };
    var directionsService = new google.maps.DirectionsService();

    routes.forEach(function(route){
        waitingForNResults ++;
        var request = {
            origin: route.origin,
            destination: route.destination,
            travelMode: google.maps.TravelMode.DRIVING
        };
    
        var directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions);
        directionsDisplay.setMap(map);
    
        directionsService.route(request, function(result, status) {
            console.log(result);
    
            if (status == google.maps.DirectionsStatus.OK) {
                waitingForNResults --;
                directionsDisplay.setDirections(result);
                var path = result.routes[0].overview_path;
                paths.push(path);
                var lengthOfPath = google.maps.geometry.spherical.computeLength(path);
                if (lengthOfPath > maxDistance) {
                    maxDistance = lengthOfPath;
                }
                if (waitingForNResults == 0) {
                    //adjust zoom to fit routes
                    var latlngbounds = new google.maps.LatLngBounds();

                    for ( var i = 0; i < markers.length; i++ ) {
                      latlngbounds.extend(markers[i] );
                    }
                    map.fitBounds(latlngbounds);
                    map.setCenter(latlngbounds.getCenter( ));
                    startMainLoop();
                }
            }
        });
});

   // var path1 = calcRouteAndAddPath("chicago, il","los angeles, ca");
   // var path2 = calcRouteAndAddPath("new orleans, la","los angeles, ca");

}



function calcRouteAndAddPath(start,end) {
    waitingForNResults ++;
    var request = {
      origin:start, 
      destination:end,
      travelMode: google.maps.DirectionsTravelMode.DRIVING
    };

    directionsService.route(request, function(result, status) {
        if (status == google.maps.DirectionsStatus.OK) {
            waitingForNResults --;
            directionsDisplay.setDirections(result);
            var path = result.routes[0].overview_path;
            /*
            for (var i = 0; i < path.length; i++) { 
              var marker = new google.maps.Marker({ position: path[i], map: map }); 
            } */
            paths.push(path);
            if (waitingForNResults == 0) {
                startMainLoop();
            }
        }
    });
}


// Main loop

function mainLoop() {

    // enemies walk
    for (e=0; e < enemiesAndPaths.length; e++){
        enemy = enemiesAndPaths[e].enemy;
        path = paths[enemiesAndPaths[e].path];
        if ((enemy.speed == 1 && j%3 == 0) ||
            (enemy.speed == 2 && j%2 == 0) ||
            (enemy.speed == 3 && j%1 == 0)) {
                enemy.currentPositionInPath++;
                if (enemy.currentPositionInPath < path.length) {
                    var latlng = path[enemy.currentPositionInPath];
                    enemy.setEnemyPosition(latlng);
                } else {
                    mainTower.setLife(mainTower.life - 1);

					document.getElementById("mainTowerLife").innerHTML = mainTower.getLife();

                    enemy.removeFromMap();
                    enemiesAndPaths.splice(e,1);
                }
            }
    }
    
    // charge defense towers
    defenseTowersAndCircles.forEach(function(defenseTowersAndCircle) {
        defenseTower = defenseTowersAndCircle.tower;
        if(j%defenseTower.reloadTime == 0) {
            defenseTower.raiseChargeIn(10);
        }
    });

    // fire defense towers
    for (e=0; e < enemiesAndPaths.length; e++){
        var enemy = enemiesAndPaths[e].enemy;
        for (dt=0; dt < defenseTowersAndCircles.length; dt++) {
            defenseTower = defenseTowersAndCircles[dt].tower;
            distance = google.maps.geometry.spherical.computeDistanceBetween(enemy.getPosition(), defenseTower.getPosition());
            if ((distance <= calcRelativeRadius(defenseTower.range)) && (defenseTower.charge == 100)) {
                //fire
                enemy.reduceLifeIn(defenseTower.damage);
                defenseTower.discharge();

                var circle = defenseTowersAndCircles[dt].circle;
                circle.blink();
                //enemy died?
                if (enemy.life <= 0) {
                    addMoney(enemy.valueOfKilling);
                    deadEnemies[enemy.type - 1] = deadEnemies[enemy.type - 1] + 1;
                    console.log('deadEnemies[enemy.type - 1]: ', deadEnemies[enemy.type - 1]);
                    enemy.removeFromMap();
                    enemiesAndPaths.splice(e,1);
                }
            }
        }
    }

    // create enemies (a cada 20 passagens do main loop)
    if ((j%20 == 0) && !stopCreateEnemies) {
        totalEnemies++;
        var type = random([level.enemyProportions[0]*10,level.enemyProportions[1]*10,level.enemyProportions[2]*10], [1,2,3])
        var p = Math.floor(Math.random()*paths.length)  // sorteia entre os paths disponívieis
        path = paths[p];
        enemiesAndPaths.push({enemy:EnemyFactory.createEnemy(type, map, path[0]), path:p});
    }

    // stopCreateEnemies?
    nEnemies = level.numberOfEnemies; 
    if (totalEnemies >= nEnemies) {
        stopCreateEnemies = true;
    }

    // gameOver? 
    if (mainTower.life <= 0) {
		score=10*deadEnemies[0]+50*deadEnemies[1]+80*deadEnemies[2]-(2*createdTowers[0]+4*createdTowers[1]+8*createdTowers[2]);
		if(score<0){score=0;}
		$("#gameOver").fadeIn();
		$("#gameOver").append("<div id='result' class='txt'>GAME OVER!</div><div id='overTop'>"
			+"<div class='txt'>Inimigos</div>"
			+"<div class='overIni'><span><img src='img/ini1.png'/></span><span class='overtxt'>x"+deadEnemies[0]+"</span></div>"
			+"<div class='overIni'><span><img src='img/ini2.png'/></span><span class='overtxt'>x"+deadEnemies[1]+"</span></div>"
			+"<div class='overIni'><span><img src='img/ini3.png'/></span><span class='overtxt'>x"+deadEnemies[2]+"</span></div>"
		+"</div>"
		+"<div id='overBottom'>"
			+"<div class='txt'>Torres</div>"
			+"<div class='overIni'><span><img src='img/tower1.png'/></span><span class='overtxt'>x"+createdTowers[0]+"</span></div>"
			+"<div class='overIni'><span><img src='img/tower2.png'/></span><span class='overtxt'>x"+createdTowers[1]+"</span></div>"
			+"<div class='overIni'><span><img src='img/tower3.png'/></span><span class='overtxt'>x"+createdTowers[2]+"</span></div>"
		+"</div><div id='score'>Score: "+score+"</div>");
        /*alert("GAME OVER! \n\n" + 
                "Inimigos: Tipo 1 - " + deadEnemies[0] + "\n" + 
                "               Tipo 2 - " + deadEnemies[1] + "\n" +
                "               Tipo 3 - " + deadEnemies[2] + "\n" +
                "Torres: \Tipo \t Qntd\n"+ 
                "                1        "+ createdTowers[0] + "\n" + 
                "                2        "+ createdTowers[1] + "\n" +  
                "                3        "+ createdTowers[2]);*/
        $("#game").hide();

        // resetar todas as variaveis
        resetVariables();
    } else if  (enemiesAndPaths.length == 0 && stopCreateEnemies == true) {
		score=(mainTower.life)*100+10*deadEnemies[0]+50*deadEnemies[1]+80*deadEnemies[2]-(2*createdTowers[0]+4*createdTowers[1]+8*createdTowers[2]);
		if(score<0){score=0;}
		$("#gameOver").fadeIn();
		$("#gameOver").append("<div id='result' class='txt'>GANHOU!</div><div id='overTop'>"
			+"<div class='txt'>Inimigos</div>"
			+"<div class='overIni'><span><img src='img/ini1.png'/></span><span class='overtxt'>x"+deadEnemies[0]+"</span></div>"
			+"<div class='overIni'><span><img src='img/ini2.png'/></span><span class='overtxt'>x"+deadEnemies[1]+"</span></div>"
			+"<div class='overIni'><span><img src='img/ini3.png'/></span><span class='overtxt'>x"+deadEnemies[2]+"</span></div>"
		+"</div>"
		+"<div id='overBottom'>"
			+"<div class='txt'>Torres</div>"
			+"<div class='overIni'><span><img src='img/tower1.png'/></span><span class='overtxt'>x"+createdTowers[0]+"</span></div>"
			+"<div class='overIni'><span><img src='img/tower2.png'/></span><span class='overtxt'>x"+createdTowers[1]+"</span></div>"
			+"<div class='overIni'><span><img src='img/tower3.png'/></span><span class='overtxt'>x"+createdTowers[2]+"</span></div>"
		+"</div><div id='score'>Score: "+score+"</div>");
        // game ended? 
        /*alert("GANHOU! \n\n" + 
                "Vida da torre principal: " + mainTower.life + "\n" + 
                "Inimigos: Tipo 1 - " + deadEnemies[0] + "\n" + 
                "               Tipo 2 - " + deadEnemies[1] + "\n" +
                "               Tipo 3 - " + deadEnemies[2] + "\n" +
                "Torres: \Tipo \t Qntd\n"+ 
                "                1        "+ createdTowers[0] + "\n" + 
                "                2        "+ createdTowers[1] + "\n" +  
                "                3        "+ createdTowers[2]);*/
        $("#game").hide();
        // resetar todas as variaveis
        resetVariables();
    } else {
        // repeat main loop
        setTimeout("mainLoop()",100);
        j++;
    }
}

function resetVariables() {
    money = 0;
    paths = [];
    waitingForNResults = 0;
    defenseTowersAndCircles = []; //array of {tower:t, circle:circle}
    maxDistance = 0; // distance of the biggest path
    level = null;
    j = 1;
    timer_is_on = false;
    enemiesAndPaths = [];
    stopCreateEnemies = false;
    totalEnemies = 0;
    mainTower = null;
}

function startMainLoop() {
    if (!timer_is_on) {
        timer_is_on=1;
        mainLoop();
    }
}

// Auxiliar functions
function random(weighs, values) {
    //example of use: random([10,20,70], ["a","b","c"])
    var totalweight=eval(weighs.join("+")); //get total weight (in this case, 10)
    var weighedvalues=[]; //new array to hold "weighted" fruits
    var currentvalueindex=0;
    
    for (var i=0; i<values.length; i++) {
        for (var j=0; j<weighs[i]; j++) {
            weighedvalues.push(values[i]);
        }
    }

    return weighedvalues[Math.floor(Math.random()*totalweight)];
}



// Control of defense towers

function addTower(type, latitude, longitude) {
    var position = new google.maps.LatLng(latitude, longitude);

    if (priceOfType(type) > money) {
        blinkMoney();
    } else {
        var def_tower = DefenseTowerFactory.create({position:position, type:type, map:map});
        createdTowers[type-1]++;
        subtractMoney(def_tower.price);
        hideContextMenu();
        var circle = newCircle(type, position);
        defenseTowersAndCircles.push({tower:def_tower, circle:circle});
    }
}

function hideContextMenu() {
    $('.contextmenu').fadeOut();
}

function showContextMenu(currentLatLng) {
    var projection;
    var contextmenuDir;
    projection = map.getProjection() ;
    $('.contextmenu').remove();
    contextmenuDir = document.createElement("div");
    contextmenuDir.className  = 'contextmenu';
    contextmenuDir.innerHTML = 
        "<div class='def_tower_button' id='add_1' onClick='addTower(1," + currentLatLng.lat() + ',' + currentLatLng.lng() + ")' style='position: relative; clear: both;'><img class='towerImg' src='img/tower1-th.png'/><img class='dmg' src='img/damage.png'/><span class='val'>20</span><img class='money' src='img/money.png'/><span class='val'>50</span><img class='speed' src='img/speed.png'/><span class='val'>Rapido</span></div>"+
        "<div class='def_tower_button' id='add_2' onClick='addTower(2," + currentLatLng.lat() + ',' + currentLatLng.lng() + ")' style='position: relative; clear: both;'><img class='towerImg' src='img/tower2-th.png'/><img class='dmg' src='img/damage.png'/><span class='val'>30</span><img class='money' src='img/money.png'/><span class='val'>80</span><img class='speed' src='img/speed.png'/><span class='val'>Medio</span></div>"+
        "<div class='def_tower_button' id='add_3' onClick='addTower(3," + currentLatLng.lat() + ',' + currentLatLng.lng() + ")' style='position: relative; clear: both;'><img class='towerImg' src='img/tower3-th.png'/><img class='dmg' src='img/damage.png'/><span class='val'>40</span><img class='money' src='img/money.png'/><span class='val'>100</span><img class='speed' src='img/speed.png'/><span class='val'>Lento</span></div>";
    
    $(map.getDiv()).append(contextmenuDir);
    
    setMenuXY(currentLatLng);

    contextmenuDir.style.visibility = "visible";

    $("#add_1").hover(function(){showHover(1, currentLatLng);}, function(){hideHover();});
    $("#add_2").hover(function(){showHover(2, currentLatLng);}, function(){hideHover();});
    $("#add_3").hover(function(){showHover(3, currentLatLng);}, function(){hideHover();});
}

function showHover(type, center) {
    circleHover = newCircle(type, center);
}

function newCircle(type, center) {
    var radius = calcRelativeRadius(rangeOfType(type))/1000; //in meters
    var circle = new MapCircleOverlay(center, radius, "#FF0000", 0.8, 3, "#FF0000", 0.35);
    circle.setMap( map );
    return circle;
}

function hideHover() {
    circleHover.setMap( null );
}

function setMenuXY(currentLatLng){
    var mapWidth = $('#map_canvas').width();
    var mapHeight = $('#map_canvas').height();
    var menuWidth = $('.contextmenu').width();
    var menuHeight = $('.contextmenu').height();
    var clickedPosition = getCanvasXY(currentLatLng);
    var x = clickedPosition.x ;
    var y = clickedPosition.y ;

    if((mapWidth - x ) < menuWidth)
        x = x - menuWidth;
    if((mapHeight - y ) < menuHeight)
        y = y - menuHeight;

    $('.contextmenu').css('left',x  );
    $('.contextmenu').css('top',y );
};

function getCanvasXY(currentLatLng){
    var scale = Math.pow(2, map.getZoom());
    var nw = new google.maps.LatLng(
        map.getBounds().getNorthEast().lat(),
        map.getBounds().getSouthWest().lng()
    );
    var worldCoordinateNW = map.getProjection().fromLatLngToPoint(nw);
    var worldCoordinate = map.getProjection().fromLatLngToPoint(currentLatLng);
    var currentLatLngOffset = new google.maps.Point(
        Math.floor((worldCoordinate.x - worldCoordinateNW.x) * scale),
        Math.floor((worldCoordinate.y - worldCoordinateNW.y) * scale)
    );
    return currentLatLngOffset;
}

function calcRelativeRadius(percentual) {
    return maxDistance*percentual/100;
}

// money control
function setMoney(value) {
    money = value;
    $('#money').text(money);
}

function subtractMoney(value) {
    money = money - value;
    $('#money').text(money);
}

function addMoney(value) {
    money = money + value;
    $('#money').text(money);
}

function blinkMoney(){
	$(".contextmenu").fadeOut();
	$(".notification").fadeIn(
		function(){
			$(".notification").delay(2000).fadeOut();
		});
}